from random import random

__author__ = 'Douglas'


class Matrix:
    def __init__(self, arg0, arg1=None, arg2=0):
        if isinstance(arg0, list):
            self.__matrix = arg0
        elif isinstance(arg0, Matrix):
            self.__matrix = [row[:] for row in arg0.__matrix]
        else:
            self.__matrix = [[arg2 for _ in range(arg1)] for _ in range(arg0)]

    def __getitem__(self, i):
        return self.__matrix[i]

    def __setitem__(self, i, v):
        self.__matrix[i] = v

    def __add__(self, other):
        if self.rows == other.rows and self.columns == other.columns:
            return Matrix([[a + b for a, b in zip(self[row], other[row])] for row in range(self.rows)])
        else:
            raise ValueError("The matrices must have the same dimensions")

    def __sub__(self, other):
        if self.rows == other.rows and self.columns == other.columns:
            return Matrix([[a - b for a, b in zip(self[row], other[row])] for row in range(self.rows)])
        else:
            raise ValueError("The matrices must have the same dimensions")

    def __mul__(self, other):
        if isinstance(other, (int, float, complex)):
            return Matrix([[other * n for n in self[row]] for row in range(self.rows)])
        else:
            return Matrix([
                [sum(a * b for a, b in zip(self[row], other.get_column(column).transpose()[0])) for column in
                 range(other.columns)] for row in range(self.rows)])

    def __str__(self):
        return str(self.__matrix)

    def get_column(self, column):
        return Matrix([[vector[column]] for vector in self])

    def transpose(self):
        return Matrix([[self[row][column] for row in range(self.rows)] for column in range(self.columns)])

    def ramdomize(self, minimum, maximum):
        rand = lambda: (random() * (maximum - minimum)) + minimum
        return Matrix([[rand() for _ in range(self.columns)] for _ in range(self.rows)])

    def delete_row(self, n):
        rows = list(range(self.rows))
        rows.remove(n)
        return Matrix([self[row] for row in rows])

    def delete_column(self, n):
        columns = list(range(self.columns))
        columns.remove(n)
        return Matrix([[self[row][i] for i in columns] for row in range(self.rows)])

    def from_boolean_to_bipolar(self):
        return Matrix([[1 if self[row][column] else -1 for column in range(self.columns)] for row in range(self.rows)])

    @classmethod
    def create_identity_matrix(cls, size):
        return Matrix([[1 if column == row else 0 for column in range(size)] for row in range(size)])

    @property
    def rows(self):
        return len(self.__matrix)

    @property
    def columns(self):
        return 0 if self.rows == 0 else len(self[0])

    def clear(self):
        self.__matrix = [[0 for _ in self[row]] for row in range(self.rows)]